package com.example.sync.factory;

import com.example.server.service.SysServerService;
import com.example.sync.constant.Constant;
import com.example.sync.handler.SysASyncJobHandler;
import com.example.sync.po.SysASyncJob;
import com.example.sync.service.SysASyncJobService;
import com.example.utils.TimeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author chentao
 * @version 1.0
 * @description: TODO
 * @date 2025/3/22 下午2:27
 */
@Service
public class SysSyncFactory implements InitializingBean, DisposableBean {

    Logger logger = LoggerFactory.getLogger(getClass());

    //每次拉取任务数
    @Value("${sync.max.size:10}")
    private int maxSize;

    //最大尝试次数
    @Value("${sync.max.retry-count:10}")
    private int maxRetryCount;

    @Value("${sync.delay-sec:5}")
    private int delaySec;

    @Resource
    private SysASyncJobService sysASyncJobService;

    @Resource
    private SysServerService sysServerService;

    @Resource
    private SysASyncJobHandler sysASyncJobHandler;

    private ExecutorService executorService;

    private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;

    @Override
    public void afterPropertiesSet() throws Exception {
        logger.warn("server节点: " + sysServerService.getCurrentServerId() + " 启动中 ...");
        this.executorService = Executors.newCachedThreadPool();
        this.scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(10);
        this.scheduledThreadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    List<SysASyncJob> sysASyncJobs = sysASyncJobService.getSysASyncJob(sysServerService.getCurrentServerId(), maxSize, maxRetryCount);
                    if (!sysASyncJobs.isEmpty()) {
                        CountDownLatch countDownLatch = new CountDownLatch(sysASyncJobs.size());
                        for (SysASyncJob sysASyncJob : sysASyncJobs) {
                            executorService.execute(new SysASyncJobHandlerThread(sysASyncJob, countDownLatch));
                        }
                        countDownLatch.await();
                    }
                } catch (Exception e) {
                    logger.warn("批量处理异步任务失败: " + e.getMessage());
                }
            }
        }, 0, delaySec, TimeUnit.SECONDS);
    }

    @Override
    public void destroy() throws Exception {
        this.scheduledThreadPoolExecutor.shutdownNow();
        this.executorService.shutdownNow();
    }

    //异步任务处理线程
    class SysASyncJobHandlerThread implements Runnable {

        private SysASyncJob sysASyncJob;

        private CountDownLatch countDownLatch;

        public SysASyncJobHandlerThread(SysASyncJob sysASyncJob, CountDownLatch countDownLatch) {
            this.sysASyncJob = sysASyncJob;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            int retryCount = sysASyncJob.getRetryCount();
            try {
                sysASyncJob.setStatus(Constant.SUCCESS);
                sysASyncJobHandler.handle(sysASyncJob);
            } catch (Exception e) {
                int retryPeriod = sysASyncJobHandler.getHandler(sysASyncJob).getRetryPeriod();
                int nextRetryCount = retryCount + 1;
                Date nextRetryTime = TimeUtils.getTime(retryPeriod * (nextRetryCount));
                sysASyncJob.setRetryTime(nextRetryTime);
                if (nextRetryCount == maxRetryCount) {
                    sysASyncJob.setStatus(Constant.FAILURE);
                } else {
                    sysASyncJob.setStatus(Constant.RUNNING);
                }
                sysASyncJob.setErrorMessage(e.getMessage());
                logger.warn("处理异步任务: {} 处理失败: {}", sysASyncJob, e.getMessage());
            } finally {
                sysASyncJob.setRetryCount(retryCount + 1);
                sysASyncJob.recalculateFields();
                sysASyncJobService.saveOrUpdate(sysASyncJob);
                countDownLatch.countDown();
            }
        }
    }
}
